package com.xiaoyu.base.utils.time;

import android.text.TextUtils;

import com.xiaoyu.base.R;
import com.xiaoyu.base.app.AppContext;

import in.srain.cube.util.TimeUtils;
import in.srain.cube.util.time.DateFormat;
import in.srain.cube.util.time.TimeData;

import java.io.Serializable;
import java.util.Date;

import in.srain.cube.request.JsonData;

public final class CountDown implements Serializable {

    public static final CountDown INVALID = new CountDown();
    public final Date startTime;
    public final Date endTime;
    public final long duration;
    public boolean mIsValid = false;

    private CountDown() {
        startTime = new Date();
        endTime = new Date();
        duration = 0;
        mIsValid = false;
    }

    private CountDown(Date startTime, Date endTime, long duration) {
        this.startTime = startTime;
        this.endTime = endTime;
        this.duration = duration;
        mIsValid = true;
    }

    /**
     * NOTE: startTime maybe change.
     */
    public static CountDown fromNowByServer(int duration) {
        final Date startTime = TimeData.getInstance().getServerTime();
        final Date endTime = new Date();
        endTime.setTime(duration * 1000 + startTime.getTime());
        return new CountDown(startTime, endTime, duration);
    }

    public static CountDown fromNow(int duration) {
        return fromNow(duration * 1000L);
    }

    public static CountDown fromNow(long durationMs) {
        final Date startTime = new Date();
        final Date endTime = new Date(durationMs + startTime.getTime());
        return new CountDown(startTime, endTime, durationMs);
    }

    public static CountDown createFromJson(JsonData data) {
        if (!data.has("startTime") || !data.has("endTime") || !data.has("duration")) {
            return INVALID;
        }
        if (TextUtils.isEmpty(data.optString("startTime")) || TextUtils.isEmpty(data.optString("endTime")) || data.optLong("duration") == 0) {
            return INVALID;
        }
        final Date startTime = DateFormat.parse(data.optString("startTime"));
        final Date endTime = DateFormat.parse(data.optString("endTime"));
        final long duration = data.optLong("duration");
        return new CountDown(startTime, endTime, duration);
    }

    @Override
    public String toString() {
        if (!mIsValid) {
            return "CountDown INVALID";
        }
        return "CountDown {" +
                "startTime=" + DateFormat.format(startTime) +
                ", duration='" + duration + '\'' +
                ", endTime='" + DateFormat.format(endTime) + '\'' +
                '}';
    }

    public String JsonStringify() {
        JsonData jsonData = JsonData.newMap();
        jsonData.put("startTime", DateFormat.format(startTime));
        jsonData.put("duration", duration);
        jsonData.put("endTime", DateFormat.format(endTime));
        return jsonData.toString();
    }

    public String getExpireInTextByServers() {
        if (isExpiredByServers()) {
            return AppContext.getString(R.string.count_down_expired);
        }
        return String.format(AppContext.getString(R.string.count_down_will_expire_in), TimeUtils.secondsToShortText(AppContext.getContext(), getRemainSecondsByServers()));
    }

    public Date getStartTime() {
        return startTime;
    }

    public String getDigitalCountDownTextByServers() {
        long seconds = getRemainSecondsByServers();
        if (isExpiredByServers()) {
            return "00:00:00";
        }
        return TimeUtils.secondsToDigitalText(seconds);
    }

    public String getDigitalCountDownShortTextByServers() {
        if (isExpiredByServers()) {
            return "00:00";
        }
        long seconds = getRemainSecondsByServers();
        return TimeUtils.secondsToClockText(seconds);
    }

    public String getExpireTextCountDownTextByServers() {
        if (isExpiredByServers()) {
            return "00:00:00";
        }
        return TimeUtils.secondsToShortText(AppContext.getContext(), getRemainSecondsByServers());
    }

    public long getDuration() {
        return duration;
    }

    public long getTotalSeconds() {
        return (endTime.getTime() - startTime.getTime()) / 1000;
    }

    public long getTotalMilliSeconds() {
        return (endTime.getTime() - startTime.getTime());
    }

    public long getPassSecondsByServers() {
        return duration - getRemainSecondsByServers();
    }

    public long getRemainDaysByServers() {
        return (endTime.getTime() - TimeData.getInstance().getServerTime().getTime()) / TimeUtils.DAY_MS;
    }

    public long getRemainDays() {
        return (endTime.getTime() - System.currentTimeMillis()) / TimeUtils.DAY_MS;
    }

    public long getRemainSecondsByServers() {
        return (endTime.getTime() - TimeData.getInstance().getServerTime().getTime()) / 1000;
    }

    public long getRemainSeconds() {
        return (endTime.getTime() - System.currentTimeMillis()) / 1000;
    }

    public long getRemainMinutesByServers() {
        return (endTime.getTime() - TimeData.getInstance().getServerTime().getTime()) / (60 * 1000);
    }

    public long getRemainMinutesSeconds() {
        return (endTime.getTime() - System.currentTimeMillis()) / (60 * 1000);
    }

    public long getRemainMilliSecondsByServers() {
        return (endTime.getTime() - TimeData.getInstance().getServerTime().getTime());
    }

    public long getRemainMilliSeconds() {
        return (endTime.getTime() - System.currentTimeMillis());
    }

    public int getRemainMinutesCeilByServers() {
        return (int) Math.ceil(getRemainSecondsByServers() / 60.0);
    }

    public long getPassThoughMilliSeconds() {
        return (System.currentTimeMillis() - startTime.getTime());
    }

    public boolean isValid() {
        return mIsValid;
    }

    public boolean shouldDoUpdateByServers() {
        return mIsValid && !isExpiredByServers();
    }

    public boolean shouldDoUpdate() {
        return mIsValid && !isExpired();
    }

    public boolean isExpiredByServers() {
        return getRemainSecondsByServers() <= 0;
    }

    public boolean isExpired() {
        return getRemainSeconds() <= 0;
    }

    public boolean isExpiredByMilliSeconds() {
        return getRemainMilliSeconds() <= 0;
    }

    public long getNextUpdateTimeInSecond() {
        final long remain = getRemainSecondsByServers();
        if (remain <= 60) {
            return 1;
        } else {
            return Math.max(getRemainSecondsByServers() / 10, 60);
        }
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (!CountDown.class.isAssignableFrom(obj.getClass())) {
            return false;
        }
        if (obj == this) {
            return true;
        }
        final CountDown other = (CountDown) obj;
        if (duration != other.duration) {
            return false;
        }
        if (!startTime.equals(other.startTime)) {
            return false;
        }
        if (!endTime.equals(other.endTime)) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = hash * 53 + startTime.hashCode();
        hash = hash * 53 + endTime.hashCode();
        hash = hash * 53 + (int) duration;
        return hash;
    }
}
